#include "rio.h"

#include <stdio.h>
#include <assert.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void
test_no_buffer()
{
    const char *filename = "test_rio.buffer1";
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, -1);
    assert(fd > 0);


    // test write
    char buf1[512], buf11[512];
    memset(buf1, 'a', sizeof(buf1));
    assert(rio_writen(fd, buf1, sizeof(buf1)) == sizeof(buf1));

    char buf2[5120], buf22[5120];
    memset(buf2, 'b', sizeof(buf2));
    assert(rio_writen(fd, buf2, sizeof(buf2)) == sizeof(buf2));

    char buf3[20480], buf33[20480];
    memset(buf3, 'c', sizeof(buf3));
    assert(rio_writen(fd, buf3, sizeof(buf3)) == sizeof(buf3));

    // test read
    assert(lseek(fd, 0, SEEK_SET) == 0);
    rio_readn(fd, buf11, sizeof(buf1));
    assert(memcmp(buf1, buf11, sizeof(buf1)) == 0);

    rio_readn(fd, buf22, sizeof(buf2));
    assert(memcmp(buf2, buf22, sizeof(buf2)) == 0);

    rio_readn(fd, buf33, sizeof(buf3));
    assert(memcmp(buf3, buf33, sizeof(buf3)) == 0);

    close(fd);
}

void
test_buffer()
{
    const char *filename = "test_rio.buffer2";
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, -1);
    assert(fd > 0);

    RIOT rio;
    rio_readinitb(&rio, fd);


    // test write
    char buf1[512], buf11[512];
    memset(buf1, 'a', sizeof(buf1));
    assert(rio_writen(fd, buf1, sizeof(buf1)) == sizeof(buf1));

    char buf2[5120], buf22[5120];
    memset(buf2, 'b', sizeof(buf2));
    assert(rio_writen(fd, buf2, sizeof(buf2)) == sizeof(buf2));

    char buf3[20480], buf33[20480];
    memset(buf3, 'c', sizeof(buf3));
    assert(rio_writen(fd, buf3, sizeof(buf3)) == sizeof(buf3));

    // test read
    assert(lseek(fd, 0, SEEK_SET) == 0);
    rio_readnb(&rio, buf11, sizeof(buf1));
    assert(memcmp(buf1, buf11, sizeof(buf1)) == 0);

    rio_readnb(&rio, buf22, sizeof(buf2));
    assert(memcmp(buf2, buf22, sizeof(buf2)) == 0);

    rio_readnb(&rio, buf33, sizeof(buf3));
    assert(memcmp(buf3, buf33, sizeof(buf3)) == 0);

    close(fd);
}

void
test_buffer2()
{
    const char *filename = "test_rio.buffer3";
    int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, -1);
    assert(fd > 0);

    RIOT rio;
    rio_readinitb(&rio, fd);


    // test write
    char buf1[512], buf11[512 + 1];
    memset(buf1, 'a', sizeof(buf1));
    buf1[sizeof(buf1) - 1] = '\n';
    assert(rio_writen(fd, buf1, sizeof(buf1)) == sizeof(buf1));

    char buf2[5120], buf22[5120 + 1];
    memset(buf2, 'b', sizeof(buf2));
    buf2[sizeof(buf2) - 1] = '\n';
    assert(rio_writen(fd, buf2, sizeof(buf2)) == sizeof(buf2));

    char buf3[20480], buf33[20480 + 1];
    memset(buf3, 'c', sizeof(buf3));
    buf3[sizeof(buf3) - 1] = '\n';
    assert(rio_writen(fd, buf3, sizeof(buf3)) == sizeof(buf3));

    // test read
    const int small = 5;
    assert(lseek(fd, 0, SEEK_SET) == 0);
    rio_readnb(&rio, buf11, small);
    rio_readlineb(&rio, buf11 + small, sizeof(buf11) - small);
    assert(memcmp(buf1, buf11, sizeof(buf1)) == 0);

    rio_readnb(&rio, buf22, small);
    rio_readlineb(&rio, buf22 + small, sizeof(buf22) - small);
    assert(memcmp(buf2, buf22, sizeof(buf2)) == 0);

    rio_readnb(&rio, buf33, small);
    rio_readlineb(&rio, buf33 + small, sizeof(buf33) - small);
    assert(memcmp(buf3, buf33, sizeof(buf3)) == 0);

    close(fd);
}

int
main()
{
    test_no_buffer();
    test_buffer();
    test_buffer2();
    return 0;
}
